//
//  QNMacros.h
//  QNReuseTool
//
//  Created by rsh on 2019/10/15.
//  Copyright © 2019年 rsh. All rights reserved.
//

#import <UIKit/UIKit.h>

#ifndef __OPTIMIZE__
#define NSLog(format, ...) fprintf(stderr, "[时间轴]: %s\n[文件名]: %s\n[函数名]: %s [行号]: %d \n[输出值]: %s\n\n", [[NSString stringWithFormat:@"%@", [NSDate date]] UTF8String], [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __FUNCTION__, __LINE__, [[NSString stringWithFormat:format, ## __VA_ARGS__] UTF8String])
#else
#define NSLog(...) {}
#endif

// Application
#define QNApplication                           UIApplication.sharedApplication
#define QNKeywindow                             UIApplication.sharedApplication.keyWindow
#define QNRootViewController                    UIApplication.sharedApplication.keyWindow.rootViewController
#define QNAppdelegate                           UIApplication.sharedApplication.delegate

// UserDefaults
#define QNUserDefaults                          NSUserDefaults.standardUserDefaults

// System
#define QNAppVersion                            [NSBundle.mainBundle.infoDictionary objectForKey:@"CFBundleShortVersionString"]
#define QNUserDefaults                          NSUserDefaults.standardUserDefaults
#define QNUserDefaultsGet(key)                  [NSUserDefaults.standardUserDefaults valueForKey:key]
#define QNUserDefaultsSet(value, key)           \
({\
    [NSUserDefaults.standardUserDefaults setValue:value forKey:key];\
    [NSUserDefaults.standardUserDefaults synchronize];\
})
#define QNAppFirstLaunch                        \
({\
    BOOL result = NO;\
    NSString *version = QNUserDefaultsGet(QNAppVersionKey);\
    if (![version isEqualToString:QNAppVersion]) {\
        QNUserDefaultsSet(QNAppVersion, QNAppVersionKey);\
        result = YES;\
    }\
    result;\
})

// NSFileManager
#define QNFileManager                           NSFileManager.defaultManager
#define QNFileDocumentPath                      NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject
#define QNFileCachePath                         NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject
#define QNFileTempPath                          NSTemporaryDirectory()
#define QNFileSize(path)                        [QNFileManager attributesOfItemAtPath:path error:nil].fileSize

#define QNScreenBounds                          UIScreen.mainScreen.bounds
#define QNScreenSize                            UIScreen.mainScreen.bounds.size
#define QNScreenWidth                           UIScreen.mainScreen.bounds.size.width
#define QNScreenHeight                          UIScreen.mainScreen.bounds.size.height

#define QNScreenMaxLength                       MAX(QNScreenWidth, QNScreenHeight)
#define QNScreenMinLength                       MIN(QNScreenWidth, QNScreenHeight)
#define QNScale(float)                          float * (QNScreenWidth / 375.0)
#define QNStatusBarH                            [UIApplication sharedApplication].statusBarFrame.size.height
#define QNNavBarHeight                          (44 + QNStatusBarH)
#define QNTabBarHeight                          (QNPhoneX ? 83.0 : 49.0)

// Device Type
#define QNIpad                                  UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad
#define QNPhone                                 UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone
#define QNPhoneS                                (QNPhone && (QNScreenMaxLength / QNScreenMinLength == 736.0 / 414.0))
#define QNPhoneX                                (QNPhone && (QNScreenMaxLength / QNScreenMinLength >= 812.0 / 375.0))
#define QNSystemAvailable(version)              @available(iOS version, *)

// Weak
#define QNWeak(type)                          __weak typeof(type) weak##type = type

// UIFont
#define QNFont(font)                            [UIFont systemFontOfSize:font]
#define QNBFont(font)                           [UIFont boldSystemFontOfSize:font]

// UIColor
#define QNColor(r, g, b, a)                     [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]
#define QNColorHexAlpha(hexNumber, a)           [UIColor colorWithRed:(((float)((hexNumber & 0xFF0000) >> 16)) / 255.0) \
                                                green:(((float)((hexNumber & 0xFF00) >> 8)) / 255.0) \
                                                blue:(((float)(hexNumber & 0xFF)) / 255.0) alpha:a]
#define QNColorHex(hexNumber)                   QNColorHexAlpha(hexNumber, 1.0)
#define QNColorRandom                           QNColor(arc4random_uniform(256),\
                                                        arc4random_uniform(256),\
                                                        arc4random_uniform(256), 1.0)

// UIImage
#define QNImage(name)                           [UIImage imageNamed:name]
#define QNImageWithHexColor(hexNumber, alpha)              \
({\
    CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);\
    UIGraphicsBeginImageContext(rect.size);\
    CGContextRef context = UIGraphicsGetCurrentContext();\
    CGContextSetFillColorWithColor(context, [[QNColorHex(hexNumber) colorWithAlphaComponent:alpha] CGColor]);\
    CGContextFillRect(context, rect);\
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();\
    UIGraphicsEndImageContext();\
    image;\
})
#define QNImageOriginal(name)                   [QNImage(name) imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
#define QNImageStretch(name, wscale, hscale)    \
({\
    UIImage *image = QNImage(name); \
    [image stretchableImageWithLeftCapWidth:image.size.width * wscale \
    topCapHeight:image.size.height * hscale];\
})

// UIView
#define QNViewBorderSet(view, width)                            [view.layer setBorderWidth:width]
#define QNViewBorderColorSet(view, UIColor)                     [view.layer setBorderColor:UIColor.CGColor]
#define QNViewCornerRadiusSet(view, radius)                     [view.layer setCornerRadius:radius]
#define QNViewMasksToBoundsSet(view, bool)                      [view.layer setMasksToBounds:bool]
#define QNViewBackgroundColorSet(view, color)                   [view setBackgroundColor:color]
#define QNViewTargetActionSet(view, target, SEL, UIControlEvents) \
        [view addTarget:target action:SEL forControlEvents:UIControlEvents]

// UIButton
#define QNButtonExclusiveTouchSet(bool)                         [UIButton.appearance setExclusiveTouch:bool];
#define QNButton(UIButtonType)                                  [UIButton buttonWithType:UIButtonType]
#define QNButtonTitleSet(button, title, UIControlState)         [button setTitle:title forState:UIControlState]
#define QNButtonTitleFontSet(button, font)                      [button.titleLabel setFont:font]
#define QNButtonImageSet(button, image, UIControlState)         [button setImage:image forState:UIControlState]
#define QNButtonBgImageSet(button, image, UIControlState)       [button setBackgroundImage:image forState:UIControlState]
#define QNButtonTitleEdgeSet(button, t, l, b, r)                [button setTitleEdgeInsets:(UIEdgeInsets){t, l, b, r}]
#define QNButtonTitleColorSet(button, color, UIControlState)    [button setTitleColor:color forState:UIControlState]
#define QNButtonImageEdgeSet(button, t, l, b, r)                [button setImageEdgeInsets:(UIEdgeInsets){t, l, b, r}]
#define QNButtonImageHorizontalSet(button, spacing, offset) \
({\
    NSString *titleString = [button titleForState:UIControlStateNormal]?:@"";\
    NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:titleString attributes:@{NSFontAttributeName : button.titleLabel.font}];\
    CGSize titleSize = [attributedString boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil].size;\
    CGSize imageSize = [button imageForState:UIControlStateNormal].size;\
    CGFloat titleHorizontalDiff = imageSize.width;\
    button.titleEdgeInsets = UIEdgeInsetsMake(offset, -titleHorizontalDiff, 0, 0);\
    CGFloat imageHorizontalDiff = titleSize.width + spacing * 2;\
    button.imageEdgeInsets = UIEdgeInsetsMake(offset, imageHorizontalDiff, 0, -imageHorizontalDiff);\
    button;\
})

// UIBarButtonItem
#define QNBarButtonTitleItemSet(title, obsever, SEL)            [UIBarButtonItem.alloc initWithTitle:title\
                                                                style:UIBarButtonItemStylePlain\
                                                                target:obsever action:SEL]
#define QNBarButtonImageItemSet(image, obsever, SEL)            [[UIBarButtonItem alloc] initWithImage:image\
                                                                style:UIBarButtonItemStylePlain\
                                                                target:obsever action:SEL]

// Base Class
#define QNRoundf(number, decimal)                               roundf(number * pow(10.0, decimal)) / pow(10.0, decimal)
#define QNDegreesToRadian(x)                                    (M_PI * (x) / 180.0)
#define QNRadianToASDegrees(radian)                             (radian * 180.0) / (M_PI)
#define QNEntryTime                                             CFAbsoluteTime entry = CFAbsoluteTimeGetCurrent();
#define QNExitTime                                              QNLogDebug(@"Time-consuming: %f", CFAbsoluteTimeGetCurrent() - entry)

// NSString
#define QNStringFormat(format, ...)             [NSString stringWithFormat:(format), ##__VA_ARGS__]
#define QNStringEmpty(string)                   ([string isKindOfClass:NSNull.class] || string.length == 0)

// NSArray
#define QNArrayEmpty(array)                     ([array isKindOfClass:NSNull.class] || array.count == 0)

// NSDictionary
#define QNDictionaryEmpty(dic)                  ([dic isKindOfClass:NSNull.class] || dic.allKeys == 0)

// NSDate
#define QNCurrentTimestamp                      [NSString stringWithFormat:@"%ld", (long)[NSDate.date timeIntervalSince1970]]
#define QNDateStringFromTimestamp(timestamp, format)    \
({\
    NSDate *date               = [NSDate dateWithTimeIntervalSince1970:timestamp];\
    NSDateFormatter *formatter = NSDateFormatter.alloc.init;\
    formatter.dateFormat = format;\
    [formatter stringFromDate: date];\
})
#define QNDateString(date, format)              \
({\
    NSDateFormatter *formatter = NSDateFormatter.alloc.init;\
    formatter.dateFormat =  format;\
    [formatter stringFromDate:date];\
})

// NSNotification
#define QNNotificationCenter                                    NSNotificationCenter.defaultCenter
#define QNNotificationNameSet(name)                             QNStringFormat(@"QNNotificationName_%@", name)
#define QNNotificationSend(name, msg)                           \
({\
    dispatch_async(dispatch_get_main_queue(), ^{\
        [QNNotificationCenter postNotificationName:name object:msg];\
    });\
})

// GCD
#define QNDispatch_After(delay, block)  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, \
                                        (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), block)
#define QNDispatch_Once(block)          static dispatch_once_t onceToken; dispatch_once(&onceToken, block);
#define QNDispatch_Async(block)         dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block)
#define QNDispatch_Main(block)          dispatch_async(dispatch_get_main_queue(), block)

